#include <iostream>
#include <SDL/SDL.h>
#include <cassert>

#include "fountain.h"
#include "highground.h"
#include "map.h"
#include "object.h"
#include "objects.h"
#include "server.h"
#include "spells.h"
#include "wizard.h"

Map* map;
Server* server;
Objects objects;

unsigned phase;
unsigned round;

unsigned int turnTicks = 0;

void nextTurn();

int main(int argc, char *argv[]) {
	if( SDL_Init(SDL_INIT_TIMER) < 0 ) {
		std::cout << "Unable to initialise SDL : "
				  << SDL_GetError() << std::endl;
		exit(1);
	}
	atexit(SDL_Quit);
	std::cout << "hgserver: initialising SDLNet" << std::endl;
	SDLNet_Init();
	atexit(SDLNet_Quit);
	
	srand(time(NULL));
	
	map = new Map();
	map->setSize(128, 128);
	map->initialise();
	//map->subdivideDisplace(100, 0.7, 6);
	map->subdivideDisplace(100, 0.7, 4);
	
	phase = PHASE_MOVEMENT;
	round = 1;

	objects.addFountain(0, 0);
	objects.addFountain(map->getWidth() - 1, 0);
	objects.addFountain(0, map->getHeight() - 1);
	
	std::cout << "hgserver: establishing server socket" << std::endl;
	server = new Server(0x1234, 4);
	std::cout << "hgserver: awaiting data" << std::endl;
	unsigned int ip, newClient, newX, newY;
	
	while (1) {
		// deal with new clients
		while (server->addClient() != 0) {
			newClient = server->getNClients() - 1;
			ip = server->getClientIp(newClient);
			std::cout << "hgserver: "
			          << ((ip >> 0) & 0xff) << "."
			          << ((ip >> 4) & 0xff) << "."
			          << ((ip >> 8) & 0xff) << "."
			          << ((ip >> 12) & 0xff) << ":"
			          << server->getClientPort(newClient)
			          << " connected" << std::endl;
			server->sendYou(newClient);
			server->sendMap(newClient);
			server->sendAddFountain(newClient, 0, 0); 
			server->sendAddFountain(newClient, map->getWidth() - 1, 0);
			server->sendAddFountain(newClient, 0, map->getHeight() - 1);
			// Give the client a wizard on a random square.
			newX = rand() % map->getWidth();
			newY = rand() % map->getHeight();
			objects.addWizard(newX, newY, newClient);
			// Send the new client the data about the existing wizards
			for (unsigned int i = 0; i < objects.getNWizards(); ++i) {
				server->sendNewWizard(newClient, objects.getWizard(i)->getX(), 
                              objects.getWizard(i)->getY(), 
                              objects.getWizard(i)->getClientId());
			}
			// send the new client info on all the clients (inc. himself).
			for (unsigned int i = 0; i < server->getNClients(); ++i) {
				server->sendNewClientInfo(newClient, i,
				                  server->getIsClientConnected(i),
				                  server->getClientName(i));
			}
	
			for (unsigned int i = 0; i < server->getNClients() - 1; ++i) {
				if (server->getIsClientConnected(i) == false) {
					continue;
				}
				// send the old clients info on the new client
				
				server->sendNewClientInfo(i, newClient,
				                  server->getIsClientConnected(newClient),
				                  server->getClientName(newClient));
				
				// Send the old clients the data about the new wizard
				unsigned int newWizard = objects.getNWizards() - 1;
				server->sendNewWizard(i, objects.getWizard(newWizard)->getX(), 
                              objects.getWizard(newWizard)->getY(), 
                             objects.getWizard(newWizard)->getClientId());
			}
			nextTurn();	// temporary
		}
		
		// deal with turns
		if (SDL_GetTicks() - turnTicks > (1000 * 20)) {
			nextTurn();
		}
		
		server->getMessages();
		SDL_Delay(20);
	}
	return EXIT_SUCCESS;
}

// advances the turn.
// is it just me, or is this excessively complicated? oh well
void nextTurn() {
	unsigned cHasCast = 0, cHasMoved = 0;
	for (unsigned i = 0; i < objects.getNWizards(); ++i) {
		if (objects.getWizard(i)->getHasCast()) {
			++cHasCast;
		}
	}
	for (unsigned i = 0; i < objects.getNWizards(); ++i) {
		if (objects.getWizard(i)->getHasMoved()) {
			++cHasMoved;
		}
	}
	for (unsigned i = 0; i < objects.getNWizards(); ++i) {
		if (objects.getWizard(i)->getIsMyTurn()) {
			std::cout << i << "'s turn ends" << std::endl;
			objects.getWizard(i)->setIsMyTurn(false);
			if (phase == PHASE_CASTING) {
				objects.getWizard(i)->setHasCast(true);
				++cHasCast;
				if (cHasCast == objects.getNWizards()) {
					std::cout << "Movement phase" << std::endl;
					server->sendNewPhase(PHASE_MOVEMENT);
					phase = PHASE_MOVEMENT;
				}
			} else if (phase == PHASE_MOVEMENT) {
				objects.getWizard(i)->setHasMoved(true);
				++cHasMoved;
				if (cHasMoved == objects.getNWizards()) {
					++round;
					std::cout << "New round:" << round << std::endl;
					server->sendNewRound();
					// TODO: other stuff like flood etc here !!!!!!!!!!
					std::cout << "Casting phase" << std::endl;
					server->sendNewPhase(PHASE_CASTING);
					phase = PHASE_CASTING;
					for (unsigned j = 0; j < objects.getNWizards(); ++j) {
						objects.getWizard(j)->setHasCast(false);
						objects.getWizard(j)->setHasMoved(false);
					}
					cHasCast = 0;
					cHasMoved = 0;
					// temporary hack to remove casting phase (we have no spells atm)
					std::cout << "Movement phase" << std::endl;
					server->sendNewPhase(PHASE_MOVEMENT);
					phase = PHASE_MOVEMENT;
				}
			}
		}
	}
	int found = 0;
	if (phase == PHASE_CASTING) {
		for (unsigned i = 0; i < objects.getNWizards(); ++i) {
			if (!objects.getWizard(i)->getHasCast()) {
				if ((rand() % (objects.getNWizards() - cHasCast - found))
				    == 0) {
					std::cout << "its now " << i << "'s turn" << std::endl;
					server->sendNewTurn(i);
					objects.getWizard(i)->setIsMyTurn(true);
					break;
				}
				++found;
			}
		}
	} else if (phase == PHASE_MOVEMENT) {
		for (unsigned i = 0; i < objects.getNWizards(); ++i) {
			if (!objects.getWizard(i)->getHasMoved()) {
				if ((rand() % (objects.getNWizards() - cHasMoved - found))
				    == 0) {
					std::cout << "its now " << i << "'s turn" << std::endl;
					server->sendNewTurn(i);
					objects.getWizard(i)->setIsMyTurn(true);
					break;
				}
				++found;
			}
		}
	}
	turnTicks = SDL_GetTicks();
}

